﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
using Fcdbas.Core.Net ;
using FileTransferProtocol;
using Fcdbas.Core.Util ;
using System.Threading ;

namespace FileTransferClient
{
   
    class FileSendClient :  FileTransferClient
    {
        //private Dictionary<long,ReceiveSync> RecSyncs = new Dictionary<long,ReceiveSync> ();
        private Dictionary<long, NetSession> SendSessions = new Dictionary<long, NetSession>();
        public static string LogPath;
        #region Constructor

       

        public FileSendClient(OnEventDelegate eventDelegate, TransferHead head)
            : base(eventDelegate,head)
        {
            LogPath = AppDomain.CurrentDomain.BaseDirectory + "UpLoadLog";
        }

        #endregion

        #region Methods
        private DateTime sendDt = DateTime.Now;
        private bool ReadAndSend(ISocketConnection Connection, NetSession Session)
        {
            if (Session.FileBlock.Complated)
                return true;
            if (Session.FileBlock.FStream == null)
                Session.FileBlock.FStream = new FileStream(Session.FileBlock.FileName, FileMode.Open, FileAccess.Read);
            FileStream fs = Session.FileBlock.FStream;
            //int nCount = 0;

            byte[] read = new byte[ConstValue.SendSize];

            int readCount = 0;
            fs.Seek(Session.FileBlock.BeginPos + Session.FileBlock.HasTransfer, SeekOrigin.Begin);
            if (Session.FileBlock.TotalSize > Session.FileBlock.HasTransfer + ConstValue.SendSize)
            {
                Session.CmdType = FileTransferProtocol.CommandType.UpTransfer;
                readCount = fs.Read(read, 0, ConstValue.SendSize);
            }
            else
            {
                readCount = fs.Read(read, 0, (int)(Session.FileBlock.EndPos - Session.FileBlock.BeginPos - Session.FileBlock.HasTransfer) + 1);
                Session.FileBlock.Complated = true;
                Session.CmdType = FileTransferProtocol.CommandType.UpEnd;

            }
            //Session.FileBlock = session.Block;

            Session.FileBlock.CurrentSize = readCount;
            Session.FileBlock.Data = read;
            Session.FileBlock.HasTransfer = Session.FileBlock.HasTransfer + readCount;
            if (Session.FileBlock.TotalSize == Session.FileBlock.HasTransfer)
            {
                Session.FileBlock.Complated = true;
            }
            byte[] send = ObjectHelper.SerialzieObject<NetSession>(Session);

            Connection.BeginSend(send);
            if (Session.FileBlock.Complated)
            {
                Console.WriteLine(Session.FileBlock.BlockId + " : " + readCount.ToString());
                Fcdbas.Core.Log.XTrace.WriteLine("完成的块ID: " + Session.FileBlock.BlockId, LogPath,LogPath);
               // Connection.BeginDisconnect();
                fs.Close();
            }
            //if (BlockFinished != null)
            //  {
            //      BlockFinished.Invoke(this, new BlockFinishedEventArgs(Session.FileBlock));
            //  }

            //bool AllCompleated = true;
            //foreach (FileBlock fb in Transfer.Blocks)
            //{
            //    if (!fb.Complated)
            //        AllCompleated = false;
            //}
            //if (AllCompleated && AllFinished != null)
            //{
            //    AllFinished.Invoke(this, new AllFinishedEventArgs(this.Transfer.FileInfo.FilePath + "\\" + this.Transfer.FileInfo.FileName));
            //}
            TimeSpan ts = DateTime.Now - sendDt;
            sendDt = DateTime.Now;
            Console.WriteLine("Send time:" + ts.TotalMilliseconds.ToString());
            return true;
        }
        

        
        //private void ThreadExecute(object session)
        //{
        //    ThreadSession ts = session as ThreadSession ;
        //    NetSession Session = ts.Session ;
        //    ConnectionEventArgs e = ts.Connection;
        //    FileStream fs = new FileStream(Session.FileBlock.FileName, FileMode.Open, FileAccess.Read);
        //    //int nCount = 0;

        //    byte[] read = new byte[ConstValue.SendSize];
        //    while (!Session.FileBlock.Complated && !Stop)
        //    {
        //        int readCount = 0;
        //        fs.Seek(Session.FileBlock.BeginPos + Session.FileBlock.HasTransfer, SeekOrigin.Begin);
        //        if (Session.FileBlock.TotalSize > Session.FileBlock.HasTransfer + ConstValue.SendSize)
        //        {
        //            Session.CmdType = FileTransferProtocol.CommandType.UpTransfer;
        //            readCount = fs.Read(read, 0, ConstValue.SendSize);
        //        }
        //        else
        //        {
        //            readCount = fs.Read(read, 0, (int)(Session.FileBlock.EndPos -Session.FileBlock.BeginPos - Session.FileBlock.HasTransfer) + 1);
        //            Session.FileBlock.Complated = true;
        //            Session.CmdType = FileTransferProtocol.CommandType.UpEnd;
                    
        //        }
        //        //Session.FileBlock = session.Block;

        //        Session.FileBlock.CurrentSize = readCount;
        //        Session.FileBlock.Data = read;
        //        Session.FileBlock.HasTransfer = Session.FileBlock.HasTransfer + readCount;
        //        if (Session.FileBlock.TotalSize == Session.FileBlock.HasTransfer)
        //        {
        //            Session.FileBlock.Complated = true;
        //        }
        //        byte[] send = ObjectHelper.SerialzieObject<NetSession>(Session);

        //        e.Connection.BeginSend(send);
        //        if(Session.FileBlock.Complated)
        //            Console.WriteLine(Session.FileBlock.BlockId + " : " + readCount.ToString());
        //      //  Event(Session.FileBlock);
               
        //       // Console.WriteLine(send.Length.ToString());
        //        //if (RecSyncs.Keys.Contains(e.Connection.ConnectionId))
        //        //{
        //        //    RecSyncs[e.Connection.ConnectionId].ReceiveCount++;
        //        //    while (RecSyncs[e.Connection.ConnectionId].ReceiveCount > 2)
        //        //    {
        //        //        Thread.Sleep(50);
        //        //    }
                    
        //        //}
        //    }
        //    fs.Close();
        //      //if (BlockFinished != null)
        //      //  {
        //      //      BlockFinished.Invoke(this, new BlockFinishedEventArgs(Session.FileBlock));
        //      //  }

        //        //bool AllCompleated = true;
        //        //foreach (FileBlock fb in Transfer.Blocks)
        //        //{
        //        //    if (!fb.Complated)
        //        //        AllCompleated = false;
        //        //}
        //        //if (AllCompleated && AllFinished != null)
        //        //{
        //        //    AllFinished.Invoke(this, new AllFinishedEventArgs(this.Transfer.FileInfo.FilePath + "\\" + this.Transfer.FileInfo.FileName));
        //        //}
           
        //}
        //
        #region OnConnected
        private void StartReadAndSend(ISocketConnection Connection)
        {
            
            NetSession Session = new NetSession(ConnectionState.Connected);
            foreach (FileBlock block in Transfer.Blocks)
            {
                lock(LockStartProcess)
                {
                if (!block.StartProcess)
                {
                    block.StartProcess = true;
                    Session.FileBlock = block;
                    //ThreadSession ses = new ThreadSession();
                    //ses.Connection = e;
                    //ses.Session = Session;
                    //Thread read = new Thread(new ParameterizedThreadStart(ThreadExecute));
                    //read.Start(ses);
                    SendSessions.Add(Connection.ConnectionId, Session);
                    Fcdbas.Core.Log.XTrace.WriteLine(string.Format("开始上传，连接ID为:{0},块号为 : {1}", Connection.ConnectionId, block.BlockId), LogPath);
                    block.ConnectionID = Connection.ConnectionId;
                    ReadAndSend(Connection, Session);
                    // ThreadExecute(Session, e);
                    break;
                }
                }
            }
        }
        private void SendReadyCommand(ISocketConnection Connection)
        {
            NetSession Session = new NetSession(ConnectionState.Connected);
            Session.CmdType = CommandType.UpReady;
            byte[] send = ObjectHelper.SerialzieObject<NetSession>(Session);

            Connection.BeginSend(send);
        }
        public override void OnConnected(ConnectionEventArgs e)
        {

            StringBuilder s = new StringBuilder();

            s.Append("------------------------------------------------" + "\r\n");
            s.Append("Connected - " + e.Connection.ConnectionId + "\r\n");
            s.Append(e.Connection.Host.HostType.ToString() + "\r\n");
            s.Append(e.Connection.Creator.Name + "\r\n");
            s.Append(e.Connection.Creator.EncryptType.ToString() + "\r\n");
            s.Append(e.Connection.Creator.CompressionType.ToString() + "\r\n");
            s.Append("------------------------------------------------" + "\r\n");
            
          //  Event(s.ToString());
            //RecSyncs.Add(e.Connection.ConnectionId, new ReceiveSync());
            s.Length = 0;
            SendReadyCommand(e.Connection);
            e.Connection.BeginReceive();
            //Thread.Sleep(123);

            //if (e.Connection.Host.HostType == HostType.htServer)
            //{
            //    e.Connection.BeginReceive();
            //}
            //else
            //{
            //    byte[] b = GetMessage(e.Connection.SocketHandle.ToInt32());
            //    e.Connection.BeginSend(b);
            //}

            
        }
        
        #endregion

        #region OnSent
        
        public override void OnSent(MessageEventArgs e)
        {

            if (!e.SentByServer)
            {
                StringBuilder s = new StringBuilder();

                s.Append("------------------------------------------------" + "\r\n");
                s.Append("Sent - " + e.Connection.ConnectionId + "\r\n");
                s.Append("Sent Bytes - " + e.Connection.WriteBytes.ToString() + "\r\n");
                s.Append("------------------------------------------------" + "\r\n");

               // Event(s.ToString().Trim());

                s.Length = 0;

            }
            if (SendSessions.ContainsKey(e.Connection.ConnectionId))
            {
                NetSession session = SendSessions[e.Connection.ConnectionId];
                ReadAndSend(e.Connection, session);

                if(session.FileBlock.Complated)
                {
                    SendSessions.Remove(e.Connection.ConnectionId);
                    StartReadAndSend(e.Connection);
                }
            }
            
            //if (e.Connection.Host.HostType == HostType.htServer)
            //{
    
            //    if (!e.SentByServer)
            //    {
            //        e.Connection.BeginReceive();
            //    }

            //}
            //else
            //{
            //    e.Connection.BeginReceive();
            //}

        }
        
        #endregion

        #region OnReceived
        
        public override void OnReceived(MessageEventArgs e)
        {
            if (Stop)
            {
              //  e.Connection.BeginDisconnect();
                return;
            }
            //StringBuilder s = new StringBuilder();

            //s.Append("------------------------------------------------" + "\r\n");
            //s.Append("Received - " + e.Connection.ConnectionId + "\r\n");
            //s.Append("Received Bytes - " + e.Connection.ReadBytes.ToString() + "\r\n");
            //s.Append("------------------------------------------------" + "\r\n");
           
            NetSession msg = null;
            try
            {
                msg = ObjectHelper.DeserialzieObject<NetSession>(e.Buffer);
                
                if (msg == null)
                    return;
                switch(msg.CmdType)
                {
                    case CommandType.UpTransfer:
                    case CommandType.UpEnd:
                        ProcessReceive(msg.FileBlock);
                    if (!msg.FileBlock.Complated)
                        e.Connection.BeginReceive();
                    break;
                    case CommandType.UpSucess:
                    ProcessReceive(msg.FileBlock);
                    //if (RecSyncs.Keys.Contains(e.Connection.ConnectionId))
                    //    RecSyncs[e.Connection.ConnectionId].ReceiveCount--;
                    break;
                    case CommandType.UpReady:
                    StartReadAndSend(e.Connection);
                    break;
                    
                }
                
            }
            catch (Exception ex)
            {
                Fcdbas.Core.Log.XTrace.WriteException(ex,LogPath);
                //e.Connection.BeginReceive();
                Console.WriteLine(ex.Message);
                return;
            }
           
           // e.Connection.BeginReceive();
            //SleepRandom(e.Connection.Host.HostType);

            //if (e.Connection.Host.HostType == HostType.htServer)
            //{
            //    e.Connection.BeginSend(e.Buffer);
            //}
            //else
            //{
            //    byte[] b = GetMessage(e.Connection.SocketHandle.ToInt32());
            //    e.Connection.BeginSend(b);
            //}

        }
        private int nCount = 0;
        private void ProcessReceive(FileBlock fb)
        {
            if (!ComplatedDic.Keys.Contains(fb.BlockId))
                return;
            ComplatedDic[fb.BlockId].HasTransfer = fb.HasTransfer;
            ComplatedDic[fb.BlockId].Complated  = fb.Complated;
           
            nCount++;
            if (nCount == 20)
            {
                OnTransferSum();
                nCount = 0;
            }
            if (fb.Complated)
            {
                bool allComplate = true;
                foreach (FileBlock f in ComplatedDic.Values)
                {
                    if (!f.Complated)
                    {
                        allComplate = false;
                        break;
                    }
                }
                if (allComplate)
                {
                    Stop = true;
                    OnAllFinished(this.Transfer.FileInfo.FilePath + "\\" + this.Transfer.FileInfo.FileName);

                }
            }
        }
        #endregion

        #region OnDisconnected
        
        public override void OnDisconnected(ConnectionEventArgs e)
        {

            StringBuilder s = new StringBuilder();

            s.Append("------------------------------------------------" + "\r\n");
            s.Append("Disconnected - " + e.Connection.ConnectionId + "\r\n");
            s.Append("------------------------------------------------" + "\r\n");
            if (SendSessions.ContainsKey(e.Connection.ConnectionId))
                SendSessions.Remove(e.Connection.ConnectionId);
           // Event(s.ToString());
            s.Length = 0;
            FileBlock fb = Transfer.Blocks.Find(p => p.ConnectionID == e.Connection.ConnectionId);
            if (fb != null)
            {
                if (!fb.Complated)
                    fb.StartProcess = false;
                if (SendSessions.ContainsKey(e.Connection.ConnectionId))
                    SendSessions.Remove(e.Connection.ConnectionId);
            }
            if (e.Connection != null)
            {
                e.Connection.AsClientConnection().BeginReconnect();
            }
            //if (e.Connection.Host.HostType == HostType.htServer)
            //{
            //    //------
            //}
            //else
            //{
            //    e.Connection.AsClientConnection().BeginReconnect();
            //}

        }
        
        #endregion

        #region OnException
        
        public override void OnException(ExceptionEventArgs e)
        {

            StringBuilder s = new StringBuilder();

            s.Append("------------------------------------------------" + "\r\n");
            s.Append("Exception - " + e.Exception.GetType().ToString() + "\r\n");
            s.Append("Exception Message - " + e.Exception.Message + "\r\n");

            if (e.Exception is ReconnectAttemptException)
            {
                s.Append("Attempted   - " + ((ReconnectAttemptException)e.Exception).Attempt.ToString() + "\r\n");
                s.Append("Max Reached - " + ((ReconnectAttemptException)e.Exception).MaxReached.ToString() + "\r\n");
                s.Append("------------------------------------------------" + "\r\n");
               // s.Append("Inner Error - " + ((SocketException)e.Exception.InnerException).ErrorCode.ToString() + "\r\n");
              //  s.Append("------------------------------------------------" + "\r\n");
               // s.Append("Creator - " + ((ReconnectAttemptException)e.Exception).Creator.Name + "\r\n");
               // s.Append("Creator - " + ((ReconnectAttemptException)e.Exception).Creator.EncryptType.ToString() + "\r\n");
              //  s.Append("Creator - " + ((ReconnectAttemptException)e.Exception).Creator.CompressionType.ToString() + "\r\n");

            }

            if (e.Exception is SocketException)
            {
                s.Append("Socket Error - " + ((SocketException)e.Exception).ErrorCode.ToString() + "\r\n");
            }

            s.Append("------------------------------------------------" + "\r\n");
            Fcdbas.Core.Log.XTrace.WriteLine(s.ToString(), LogPath);
           // Event(s.ToString());
            s.Length = 0;

           
            if (e.Connection != null)
            {
                FileBlock fb = Transfer.Blocks.Find(p => p.ConnectionID == e.Connection.ConnectionId);
                if (fb != null)
                {
                    if (!fb.Complated)
                        fb.StartProcess = false;
                }
                if (SendSessions.ContainsKey(e.Connection.ConnectionId))
                    SendSessions.Remove(e.Connection.ConnectionId);
                e.Connection.AsClientConnection().BeginReconnect();
            }
          
        }
        
        #endregion

        #endregion

    }
}
